Skip to main content

12 · Eino:Go 语言里最完整的 Agent 框架

仓库cloudwego/eino
Star12.7k
版本v0.9.15(v0.10 alpha 开发中)
语言Go(1.18+,重度依赖泛型)
许可证Apache 2.0
出品字节跳动 CloudWeGo
层级Framework + 内建 Runtime 能力
一句话借鉴 LangChain 和 Google ADK,但按 Go 的方式重做一遍 —— 编译期类型安全是它最大的不同

Eino 架构总览

图片来源:cloudwego/eino


一、Go 团队为什么需要它

大量高并发后端服务是 Go 写的。把 Agent 能力塞进去,之前只有两条路:裸调 HTTP API 自己写循环,或者起个 Python 服务做跨语言调用。Eino 提供了第三条:在 Go 里用和 LangChain 同级别的抽象。

Go 生态的可选项:

选项Star评价
Eino12.7k最完整,有 ADK、DeepAgent、Graph、HITL
ADK Go8.7kGoogle 官方,和 ADK Python 概念一致
裸 SDK + 手写循环——简单场景够用

二、最快的路径:ChatModelAgent

// ① 造一个 ChatModel 组件。换供应商就换这个构造函数(claude / gemini / ark / ollama…),
// 后面的代码一个字都不用改 —— 这是 Eino 组件抽象的意义
chatModel, _ := openai.NewChatModel(ctx, &openai.ChatModelConfig{
Model: "gpt-4o",
APIKey: os.Getenv("OPENAI_API_KEY"),
})

// ② 包成一个 Agent。ReAct 循环(要不要调工具、什么时候收尾)在内部处理
agent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Model: chatModel,
})

// ③ Runner 负责执行。Query 返回一个迭代器,而不是一次性结果
runner := adk.NewRunner(ctx, adk.RunnerConfig{Agent: agent})
iter := runner.Query(ctx, "Hello, who are you?")
for {
event, ok := iter.Next() // 每次拿一个事件:模型说话、调工具、工具返回……
if !ok { // ok == false 表示流结束
break
}
fmt.Println(event.Message.Content)
}

加工具:

agent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Model: chatModel,
// 嵌套两层是因为工具在底层其实是编排图里的一个「工具节点」,
// adk 只是把 compose 层的配置透传下去。写起来啰嗦,但两层是同一套东西
ToolsConfig: adk.ToolsConfig{
ToolsNodeConfig: compose.ToolsNodeConfig{
Tools: []tool.BaseTool{weatherTool, calculatorTool},
},
},
})

ReAct 循环在内部处理 —— 什么时候调工具、什么时候回答,由 Agent 自己决定。

ReAct

图片来源:cloudwego/eino


三、DeepAgent:Go 世界里的 Harness

Eino 内建了 DeepAgent —— 本专题里除 DeepAgentsClaude Agent SDK 之外,唯一自带 Harness 层的框架,也是唯一的 Go 实现:

deepAgent, _ := deep.New(ctx, &deep.Config{
ChatModel: chatModel,
// 子 Agent:主 Agent 会把子任务派给它们,各自在独立上下文里干活
SubAgents: []adk.Agent{researchAgent, codeAgent},
ToolsConfig: adk.ToolsConfig{
ToolsNodeConfig: compose.ToolsNodeConfig{
// shell / python / 搜索三件套 —— 长任务型 Agent 的标配
Tools: []tool.BaseTool{shellTool, pythonTool, webSearchTool},
},
},
})

// 用法和普通 Agent 完全一样,区别在于它会先拆解任务、列计划、再逐步执行
runner := adk.NewRunner(ctx, adk.RunnerConfig{Agent: deepAgent})
iter := runner.Query(ctx, "Analyze the sales data in report.csv and generate a summary chart")

它会拆解问题、委派子 Agent、跟踪进度,并能跑 shell、执行 Python、搜网页。能力对标 DeepAgents,语言是 Go。


四、Composition:编译期类型安全的图

需要精确控制流程时,用 compose 建图:

// 泛型参数把整张图的输入 / 输出类型钉死。节点之间类型对不上 → 编译不过,
// 而不是等到运行时第 40 分钟才炸 —— 这是 Eino 相对 Python 框架最大的不同
graph := compose.NewGraph[*Input, *Output]()

// 三种节点:Lambda 是你自己的 Go 函数,ChatModel 是模型调用,
// 另外还有 ToolsNode、Retriever、Embedding 等组件节点
graph.AddLambdaNode("validate", validateFn) // 确定性代码:先校验
graph.AddChatModelNode("generate", chatModel) // 交给模型
graph.AddLambdaNode("format", formatFn) // 确定性代码:整理输出

// 连边,START / END 是框架内置的起止哨兵
graph.AddEdge(compose.START, "validate")
graph.AddEdge("validate", "generate")
graph.AddEdge("generate", "format")
graph.AddEdge("format", compose.END)

runnable, _ := graph.Compile(ctx) // 编译:这一步会做完整的类型和结构校验
result, _ := runnable.Invoke(ctx, input) // 执行

Graph

图片来源:cloudwego/eino

这是 Eino 相对 Python 框架最大的差异

compose.NewGraph[*Input, *Output]() 这个泛型签名意味着:节点之间类型对不上,编译不过。

Eino(Go 泛型)LangGraph(Python)
类型检查编译期运行时(TypedDict 只是提示)
节点接错类型编译报错跑到那一步才炸
重构编译器帮你找全所有影响点靠测试和运气
代价泛型签名啰嗦,灵活度低写起来快

对生产系统来说,「跑到第 40 分钟才发现节点类型对不上」和「编译时就报错」,差的不是一点半点。 这是静态语言在 Agent 编排上的真实优势。

图可以变成工具

// 把上面那张确定性的图,包装成一个「工具」。
// 后两个参数是工具名和描述 —— 模型就靠这段描述决定什么时候用它
tool, _ := graphtool.NewInvokableGraphTool(graph, "data_pipeline", "Process and validate data")

agent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Model: chatModel,
ToolsConfig: adk.ToolsConfig{
ToolsNodeConfig: compose.ToolsNodeConfig{Tools: []tool.BaseTool{tool}},
},
})
// 效果:流水线内部 100% 确定可控(还有编译期类型保证),
// 而「什么时候跑这条流水线」交给模型判断 —— 混合控制的一种优雅写法

这一步很关键:把确定性流程封装成图,再作为工具交给自主 Agent,由模型决定什么时候用。这正是 01 D2 维度 说的「混合控制」的一种优雅实现 —— 确定性的部分完全可控,不确定的部分交给模型决定调不调用。


五、流式处理:框架替你处理拼接与复制

这是 Eino 一个很务实的设计:编排过程中的流处理由框架自动完成 —— 流的拼接(concatenate)、装箱(boxing)、合并(merge)、复制(copy),在节点之间传数据时自动做。

流式处理

图片来源:cloudwego/eino

组件只需要实现对自己有意义的流式范式,其余框架兜底。 比如一个 Retriever 不需要支持流式输入,框架会自动把上游的流拼成完整值再喂给它。

在 Go 里手写这套(channel 的扇出、复制、生命周期管理)是很容易出 bug 的活,框架接管掉是实实在在的价值。


六、Callback 切面

在固定切点注入日志、tracing、metrics:

切点时机
OnStart组件开始
OnEnd组件结束
OnError出错
OnStartWithStreamInput流式输入开始
OnEndWithStreamOutput流式输出结束

作用范围覆盖 components、graphs、agents。这是 Go 版的「中间件」 —— 对照 LangChain MiddlewareSpring AI Advisors,三家解决的是同一个问题。


七、Interrupt / Resume

任何 agent 或 tool 都能暂停执行等待人工输入,并从检查点恢复。框架处理状态持久化和路由。

这个能力对齐了 LangGraph 的 interrupt,在 Go 生态里是独一份。对照 01 D6 维度,属于最强的那一档(状态落盘、可跨进程恢复)。


八、项目结构与生态

项目结构

图片来源:cloudwego/eino

仓库内容
eino类型定义、流式机制、组件抽象、编排、Agent 实现、切面机制
eino-ext组件实现、callback handler、评测器、提示词优化器
eino-ext/devops可视化开发与调试
eino-examples示例应用与最佳实践

组件实现覆盖 OpenAI、Claude、Gemini、Ark(火山方舟)、Ollama、Elasticsearch 等。


九、需要清楚的短板

短板说明
版本仍是 0.xv0.9.15,API 可能变;生产要锁版本
生态规模eino-ext 799 star,集成数量远不及 LangChain
英文社区薄文档中文更全,用户群在飞书;国际社区活跃度有限
泛型样板代码compose.NewGraph[*Input, *Output]() 这类签名在复杂图里会变长
Harness 层新DeepAgent 是新加的,成熟度不及 DeepAgents
火山系倾向组件里字节 / 火山引擎的集成最完整,其他家看情况

十、什么时候用 / 什么时候别用

用它,如果

  • 后端主体是 Go —— 这一条基本就决定了
  • 要把 Agent 塞进高并发 Go 服务 —— 不用为此引入 Python 运行时
  • 看重编译期类型安全 —— 这是它相对所有 Python 框架的结构性优势
  • 需要 Go 里的 HITL / 断点续跑 —— 目前 Go 生态唯一成熟的实现
  • 在字节 / 火山引擎生态里 —— Ark 集成最完整

别用它,如果

  • 团队是 Python / Java —— 没理由为框架换语言
  • 需要最广的第三方集成 —— 差距是数量级的
  • 需要 API 长期稳定 —— 0.x 版本号是个诚实的信号
  • 依赖英文社区支持 —— 遇到问题主要靠读源码和中文文档

十一、Eino 与 ADK Go 怎么选

EinoADK Go
Star12.7k8.7k
出品字节 CloudWeGoGoogle
特色泛型类型安全编排、自动流处理、DeepAgentADK Python 概念一致、A2A、Agent Engine 部署
适合通用 Go 后端,尤其国内已在 GCP / 已用 ADK Python 的团队

多语言一致性重要就选 ADK Go,Go 侧工程质量和本地化支持重要就选 Eino。